/**
 *
 */
package com.cougil.uoc.seghismed.business.impl;

import java.util.Set;

import org.apache.log4j.Logger;

import com.cougil.uoc.seghismed.business.CipherService;
import com.cougil.uoc.seghismed.business.CoreClientService;
import com.cougil.uoc.seghismed.model.Historial;
import com.cougil.uoc.seghismed.model.Pacient;
import com.cougil.uoc.seghismed.model.Usuari;
import com.cougil.uoc.seghismed.model.Visita;
import com.cougil.uoc.seghismed.model.comunicacions.Peticio;
import com.cougil.uoc.seghismed.model.comunicacions.Resposta;
import com.cougil.uoc.seghismed.model.comunicacions.ciphed.PeticioCiphed;
import com.cougil.uoc.seghismed.model.comunicacions.ciphed.RespostaCiphed;
import com.cougil.uoc.seghismed.model.comunicacions.enums.Operacio;
import com.cougil.uoc.seghismed.model.comunicacions.enums.Resultat;
import com.cougil.uoc.seghismed.utils.SeghismedUtils;
import com.cougil.uoc.seghismed.webservice.CoreWebService;

/**
 * Classe principal que conté els mètodes principals que s'empraran per a comunicar-se
 * entre les aplicacions clients i servidora.
 *
 * @author Ignacio Cougil Jares
 */

public abstract class CoreClientServiceImpl implements CoreClientService {

	protected static final Logger logger = Logger.getLogger(CoreClientServiceImpl.class);

	// Serveis de suport emprats
	protected CipherService cipherService;

	private Usuari gestor;	// usuari gestor

	private Usuari usuari; // usuari de l'aplicació
	// Servei web consumit principal (core)
	protected CoreWebService webService;

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CoreClientService#autenticar(com.cougil.uoc.seghismed.model.comunicacions.Peticio)
	 */
	@Override
	public Resposta autenticar() {
		Usuari emisor = this.getUsuari();
		Usuari destinatari = this.getGestor();

		Peticio peticio = this.createPeticio(emisor, destinatari);

		// el client genera ni i l'envia al servidor
		Resposta resposta = this.sendAutenticar(emisor, destinatari, peticio);
		CoreClientServiceImpl.logger.debug("Resposta rebuda: ["+resposta+"]");

		boolean autenticat = false;

		// si no hi ha hagut cap error en el servidor
		if (resposta != null) {

			if (Resultat.OK.equals(resposta.getResultat())) {

				/*
				 * abans de continuar amb el protocol de Needham-Schroeder, comprovem si el servidor
				 * ja ens retorna que l'usuari ja es trobava autenticat a través del l'operació
				 * retornada
				 */

				if (Operacio.Autenticat.equals(resposta.getOperacio())) {
					// client ja autenticat previament!
					autenticat = true;

				} else {
					// el client rep ng i ni' i comprova que ni' == ni
					if (peticio.getNi().equals(resposta.getNi())) {

						peticio.setNg(resposta.getNg());
						peticio.setOperacio(Operacio.Autenticar_Gestor_Desxifrar_Ng);
						// el client envia ni i ng'
						resposta = this.sendAutenticar(emisor, destinatari, peticio);
						CoreClientServiceImpl.logger.debug("Resposta rebuda: ["+resposta+"]");

						if (Resultat.OK.equals(resposta.getResultat())) {
							/*
							 * // aquest conjunt d'operacions no calen perquè ja estem autenticats
							 * // estem autenticats, enviem una altra petició per verificar-ho
							 * peticio.setOperacio(Operacio.Autenticat); resposta =
							 * sendAutenticar(emisor, destinatari, peticio);
							 * CoreClientServiceImpl.logger
							 * .debug("Resposta rebuda: ["+resposta+"]");
							 *
							 * if (Resultat.OK.equals(resposta.getResultat())) { // l'usuari està
							 * autenticat autenticat = true; }
							 */
							autenticat = true;
						}
					}
				}
			}

			if (autenticat) {
				/*
				 * Establim de nou el valor de l'usuari, perquè en carregar la seva informació fer
				 * una nova petició, no troba els usuaris emmagatzemats perquè no coincideixen els
				 * seus valors (hashCode vs equals) amb tots els seus atributs. Ex: Pacient i el
				 * conjunt d'Al·legies associades, etc
				 */
				this.usuari = resposta.getUsuariDesti();
			}

		} else {
			CoreClientServiceImpl.logger.error("Error en el servidor - Rebuda resposta nula!!");
		}

		CoreClientServiceImpl.logger.info("Usuari [" + this.getUsuari() + "]" +
				(autenticat ? "" : " NO") + " autenticat!");

		return resposta;
	}

	private Peticio createPeticio(Usuari emisor, Usuari destinatari) {
		Peticio peticio = new Peticio();
		peticio.setNi(SeghismedUtils.getRandomInt());
		peticio.setUsuariOrigen(emisor);
		peticio.setUsuariDesti(destinatari);
		peticio.setOperacio(Operacio.Autenticar_Gestor_Desxifrar_Ni_IdUsuari);
		return peticio;
	}

	protected Usuari getGestor() {
		//DNI: 00000000-A - Gestor - gestor@seghismed.uoc.edu - OrganizationalUnit: Gestio
		if (this.gestor == null) {
			this.gestor = SeghismedUtils.getUsuariGestor(this.cipherService);
		}
		return this.gestor;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CoreClientService#getUsuari()
	 */
	public Usuari getUsuari() {
		//DNI: 00000001-B - Pacient1 - pacient1@seghismed.uoc.edu - OrganizationalUnit: Pacients
		//DNI: 00000002-C - Metge1 - metge1@seghismed.uoc.edu - OrganizationalUnit: Metges
		if (this.usuari == null) {
			this.usuari = SeghismedUtils.loadUserCert(this.cipherService,true);
		}
		return this.usuari;
	}

	/**
	 * Métode a implementar per les classe filles, emprat per obtenir el seu específic servei web
	 * associat
	 *
	 * @return servei web {@link CoreWebService} específic del servei
	 */
	protected abstract CoreWebService getWebService();

	/**
	 * Envia una petició al servidor, xifrant-la i desxifrant la resposta remesa
	 *
	 * @param emisor
	 *            {@link Usuari} usuari emisor de la petició amb quina clau privada es
	 *            xifrarà la petició
	 * @param destinatari
	 *            {@link Usuari} usuari destinatari de la petició amb quina clau pública
	 *            es xifrarà la petició
	 * @param peticio
	 *            {@link Peticio} a ésser xifrada
	 * @return Resposta desxifrada
	 */
	public Resposta sendAutenticar(Usuari emisor, Usuari destinatari, Peticio peticio) {
		// xifrem la petició
		PeticioCiphed peticioCiphed = this.cipherService.xifrarPeticio(peticio, emisor, destinatari);

		// l'enviem al servidor
		RespostaCiphed respostaCiphed = this.getWebService().autenticar(peticioCiphed);

		// desxifrem el resultat
		return this.cipherService.desxifrarResposta(respostaCiphed,emisor);
	}

	/**
	 * @param Estableix cipherService com a valor de la propietat cipherService
	 */
	public void setCipherService(CipherService cipherService) {
		this.cipherService = cipherService;
	}

	/**
	 * @param Estableix webService com a valor de la propietat webService
	 */
	public void setWebService(CoreWebService webService) {
		this.webService = webService;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CoreClientService#sortir()
	 */
	public Resposta sortir() {

		Usuari emisor = this.getUsuari();
		Usuari destinatari = this.getGestor();

		Peticio p = this.createPeticio(emisor, destinatari);

		PeticioCiphed pc = this.cipherService.xifrarPeticio(p, emisor, destinatari);

		RespostaCiphed rc = this.webService.sortir(pc);

		return this.cipherService.desxifrarResposta(rc, emisor);
	}


}
